#include "CVImgUtils.h"
#include "cvimgutilslua.h"
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>

RegisterCppObj<CVImgUtils> g_register_cvimgutils_object;

CVImgUtils::CVImgUtils()
{
	// nothing to do
}

// Return the c++ type id
int CVImgUtils::getCppTypeId()
{
	return CVIMGUTILS_OBJ_ID;
}

// Returns whether this can be cast to a given type
bool CVImgUtils::isType(int id)
{
	return id == CVIMGUTILS_OBJ_ID;
}

// Return the c++ type as a string 
std::string CVImgUtils::getCppTypeName()
{
	return "CVImgUtils";
}

// returns a description of this thing
std::string CVImgUtils::getDescription()
{
	return "Utility object for accessing some opencv functions (e.g., save and load images)";
}

// create another one of these
AbstractObject* CVImgUtils::newInstance()
{
	return new CVImgUtils;
}

// init & update
void CVImgUtils::init()
{
	// also nothing to do here
}

void CVImgUtils::update(double dt)
{
	// nope
}

// push its static functions into the given lua table
void CVImgUtils::pushStaticFuncs(lua_State* L)
{
	// push superclass static functions...
	AbstractObject::pushStaticFuncs(L);

	// just push these static funcs...
	CVImgUtilsLua::pushStaticFuncs(L);

	//static const struct luaL_Reg mylib [] = {
	//	{"InitMixer", li_initMixer},
	//	{"InitMixerDefaultSettings", li_initMixerDefaultSettings},
	//	{"LoadWAV", li_loadWAV},
	//	{"LoadMUS", li_loadMUS},
	//	{"DeleteChunk", li_deleteChunk},
	//	{"DeleteMusic", li_deleteMusic},
	//	{NULL, NULL}  /* sentinel */
	//};

	// dump them into said table
	//luaL_register(L, NULL, mylib);
}

CVImgUtils::~CVImgUtils()
{
	// nothing special to do
}

void CVImgUtils::saveImage(SimpleImage* img, std::string fn)
{
	if(img->sizeC() != 3 && img->sizeC() != 1 && img->sizeC() != 4)
	{
		LOG(logERROR) << "Cannot save image with channels != 3 (channels = " << img->sizeC();
	}
	//cv::Mat img2(cv::Size(320,240),CV_8UC3);
	LOG(logDEBUG) << "Saving an image which is " << img->sizeX() << "x" << img->sizeY() << "x" << img->sizeC();
	LOG(logDEBUG) << "Saving to filename " << fn;
	if(img->sizeC() == 3)
	{
		cv::Mat temp(img->sizeY(), img->sizeX(), CV_8UC3, img->getPtr());
		cv::Mat dimg(cv::Size(img->sizeX(), img->sizeY()), CV_8UC3);
		cv::Mat dimg2(cv::Size(img->sizeX(), img->sizeY()), CV_8UC3);
		cv::cvtColor(temp, dimg, CV_RGB2BGR);
		cv::flip(dimg, dimg2, 0);
		IplImage bla = dimg2;
		LOG(logDEBUG) << "Got this far... " << temp.rows << "x" << temp.cols;
		//cv::imwrite(fn, temp);
		cvSaveImage(fn.c_str(), &bla);
		LOG(logDEBUG) << "Done?";
	}
	if(img->sizeC() == 4)
	{
		cv::Mat temp(img->sizeY(), img->sizeX(), CV_8UC4, img->getPtr());
		cv::Mat dimg(cv::Size(img->sizeX(), img->sizeY()), CV_8UC3);
		cv::Mat dimg2(cv::Size(img->sizeX(), img->sizeY()), CV_8UC3);
		//cv::cvtColor(temp, dimg, CV_RGB2BGR);
		int fromTo[] = {0,0, 1,1, 2,2};
		cv::mixChannels(&temp, 1, &dimg, 1, fromTo, 3); 
		cv::flip(dimg, dimg2, 0);
		IplImage bla = dimg2;
		LOG(logDEBUG) << "Got this far... " << temp.rows << "x" << temp.cols;
		//cv::imwrite(fn, temp);
		cvSaveImage(fn.c_str(), &bla);
		LOG(logDEBUG) << "Done?";
	}
	else
	{
		cv::Mat temp(img->sizeY(), img->sizeX(), CV_8UC1, img->getPtr());
		cv::Mat dimg(cv::Size(img->sizeX(), img->sizeY()), CV_8UC3);
		cv::Mat dimg2(cv::Size(img->sizeX(), img->sizeY()), CV_8UC3);
		cv::cvtColor(temp, dimg, CV_GRAY2RGB);
		cv::flip(dimg, dimg2, 0);
		IplImage bla = dimg2;
		LOG(logDEBUG) << "Got this far... " << temp.rows << "x" << temp.cols;
		//cv::imwrite(fn, temp);
		cvSaveImage(fn.c_str(), &bla);
		LOG(logDEBUG) << "Done?";
	}
}

SimpleImage* CVImgUtils::loadImage(std::string fn)
{
	IplImage* tempImg = cvLoadImage(fn.c_str());
	cv::Mat loadIm(tempImg); // = cv::imread(fn);
	cv::Mat dimg(loadIm.size(), CV_8UC3);
	cv::Mat dimg2(loadIm.size(), CV_8UC3);
	cv::cvtColor(loadIm, dimg, CV_BGR2RGB);
	cv::flip(dimg, dimg2, 0);
	SimpleImage* ret = new SimpleImage();
	ret->allocateInterleaved(loadIm.cols, loadIm.rows, 3); // just assume 3
	cv::Mat_<cv::Vec3b>& tim = (cv::Mat_<cv::Vec3b>&)dimg2;
	for(int r = 0; r < dimg2.rows; ++r)
	{
		for(int c = 0; c < dimg2.cols; ++c)
		{
			for(int i = 0; i < 3; ++i)
				ret->set(c, r, i, tim(r,c)[i]);
		}
	}
	cvReleaseImage(&tempImg);
	return ret;
}